/*
 * Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the
 *       distribution.
 *    3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef __CONFIG_WLAN

#include "cmd_util.h"
#include "common/framework/net_ctrl.h"
#include "net/wlan/wlan_ext_req.h"
#include "net/wlan/wlan_frame.h"

#if PRJCONF_NET_EN

#define NONCONNECT_SNIFF            0

static enum cmd_status cmd_wlan_set_pm_dtim(char *cmd)
{
	int ret, cnt;
	uint32_t period;

	cnt = cmd_sscanf(cmd, "p=%d", &period);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_PM_DTIM, period);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_ps_mode(char *cmd)
{
	int ret, cnt;
	uint32_t ps_mode;
	uint32_t ps_ip = 0;
	uint32_t ps_cp = 0;
	wlan_ext_ps_cfg_t ps_cfg;

	if (cmd_strncmp(cmd, "enable", 6) == 0) {
		ps_mode = 1;
		cnt = cmd_sscanf((cmd + 6), " ip=%d cp=%d", &ps_ip, &ps_cp);
		if (cnt != 2) {
			ps_ip = 0;
			ps_cp = 0;
			CMD_ERR("cnt %d\n", cnt);
		}
	} else if (cmd_strncmp(cmd, "disable", 7) == 0) {
		ps_mode = 0;
	} else {
		CMD_ERR("invalid argument '%s'\n", cmd);
		return CMD_STATUS_INVALID_ARG;
	}

	cmd_memset(&ps_cfg, 0, sizeof(wlan_ext_ps_cfg_t));
	ps_cfg.ps_mode = ps_mode;
	ps_cfg.ps_idle_period = ps_ip;
	ps_cfg.ps_change_period = ps_cp;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_PS_CFG, (uint32_t)&ps_cfg);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_ampdu(char *cmd)
{
	int ret, cnt;
	int num;

	cnt = cmd_sscanf(cmd, "l=%d", &num);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_AMPDU_TXNUM, num);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_retry(char *cmd)
{
	int ret;
	int retry_cnt, cnt;

	cnt = cmd_sscanf(cmd, "n=%d", &retry_cnt);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_TX_RETRY_CNT, retry_cnt);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_pm_tx_null_period(char *cmd)
{
	int ret;
	int period, cnt;

	cnt = cmd_sscanf(cmd, "p=%d", &period);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_PM_TX_NULL_PERIOD, period);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_get_bcn_stat(char *cmd)
{
	int ret, i;
	unsigned int sum_cnt = 0;
	int sum_avg = 0;
	wlan_ext_bcn_status_t bcn_status;

	char dly_info[][20] = {
		"(<0      )",
		"(<500us  )",
		"(<1000us )",
		"(<2000us )",
		"(<4000us )",
		"(<8000us )",
		"(<16000us)",
		"(>16000us)",
	};

	cmd_memset(&bcn_status, 0, sizeof(wlan_ext_bcn_status_t));
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_BCN_STATUS, (uint32_t)&bcn_status);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	CMD_LOG(1, "\nAPP AP Beacon Delay Stat Info=================\n");
	for (i = 0; i < 8; i++) {
		CMD_LOG(1, "cnt %d %s: %d\n",
		        i, dly_info[i],
		        bcn_status.bcn_delay_cnt[i]);
		sum_cnt += bcn_status.bcn_delay_cnt[i];
	}

	if (sum_cnt)
		sum_avg = bcn_status.bcn_delay_sum / sum_cnt;

	CMD_LOG(1, "Dur: %d, Max: 0x%X, Rxed: %d, Missed: 0x%X\n",
	        bcn_status.bcn_duration,
	        bcn_status.bcn_delay_max,
	        bcn_status.bcn_rx_cnt,
	        bcn_status.bcn_miss_cnt);
	CMD_LOG(1, "Sum: %d, Cnt: %d, Ava: %d\n",
	        bcn_status.bcn_delay_sum,
	        sum_cnt,
	        sum_avg);
	CMD_LOG(1, "APP AP Beacon Delay Stat Info=================\n");

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_bcn_win_us(char *cmd)
{
	int ret;
	int bcn_win, cnt;

	cnt = cmd_sscanf(cmd, "w=%d", &bcn_win);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_BCN_WIN_US, bcn_win);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_get_cur_tx_rate(char *cmd)
{
	int ret;
	int rate;

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_TX_RATE, (int)(&rate));
	CMD_LOG(1, "current rate:%d\n", rate);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_get_pm_dtim(char *cmd)
{
	int ret;
	wlan_ext_pm_dtim_t dtim;

	cmd_memset(&dtim, 0, sizeof(wlan_ext_pm_dtim_t));
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_PM_DTIM, (int)(&dtim));
	CMD_LOG(1, "AP DTIM set:%d, STA DTIM set:%d\n",
	        dtim.pm_join_dtim_period, dtim.pm_dtim_period_extend);

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_get_cur_signal(char *cmd)
{
	int ret;
	wlan_ext_signal_t signal;

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_SIGNAL, (int)(&signal));

	CMD_LOG(1, "current rssi:%d, noise:%d\n", signal.rssi, signal.noise);

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_scan_param(char *cmd)
{
	int ret, cnt;
	int num_probes;
	int probe_delay;
	int min_dwell;
	int max_dwell;
	wlan_ext_scan_param_t param;

	cnt = cmd_sscanf(cmd, "n=%d d=%d min=%d max=%d",
	                 &num_probes, &probe_delay, &min_dwell, &max_dwell);
	if (cnt != 4) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	memset(&param, 0, sizeof(wlan_ext_scan_param_t));
	param.num_probes = num_probes;
	param.probe_delay = probe_delay;
	param.min_dwell = min_dwell;
	param.max_dwell = max_dwell;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SCAN_PARAM, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_listen_interval(char *cmd)
{
	int ret, cnt;
	uint32_t listen_interval;

	cnt = cmd_sscanf(cmd, "l=%d", &listen_interval);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_LISTEN_INTERVAL, listen_interval);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_bcn_win_cfg(char *cmd)
{
	int ret, cnt;
	int start_num, stop_num, amp_us, max_num;
	wlan_ext_bcn_win_param_set_t param;

	cnt = cmd_sscanf(cmd, "start=%d stop=%d amp=%d max=%d",
	                 &start_num, &stop_num, &amp_us, &max_num);
	if (cnt != 4) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	param.BeaconWindowAdjStartNum = start_num;
	param.BeaconWindowAdjStopNum = stop_num;
	param.BeaconWindowAdjAmpUs = amp_us;
	param.BeaconWindowMaxStartNum = max_num;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_BCN_WIN_CFG, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_scan_freq(char *cmd)
{
	int ret, cnt;
	int num;
	int chn[14];
	int freq[14];
	wlan_ext_scan_freq_t param;

	cnt = cmd_sscanf(cmd, "n=%d c=%d %d %d %d %d %d %d %d %d %d %d %d %d %d", &num,
	                 &chn[0], &chn[1], &chn[2], &chn[3], &chn[4], &chn[5], &chn[6],
	                 &chn[7], &chn[8], &chn[9], &chn[10], &chn[11], &chn[12], &chn[13]);
	if (cnt != 15) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	if (num > 14) {
		CMD_ERR("%s: invalid num:%d\n", __func__, num);
		return CMD_STATUS_ACKED;
	}
	for (int i = 0; i < num; i++) {
		freq[i] = 2407 + 5 * chn[i];
	}
	param.freq_num = num;
	param.freq_list = freq;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SCAN_FREQ, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_pm(char *cmd)
{
	int ret, cnt;
	int enable;

	cnt = cmd_sscanf(cmd, "e=%d", &enable);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}
	ret = wlan_set_ps_mode(g_wlan_netif, enable);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_get_temp_volt(char *cmd)
{
	int ret;
	wlan_ext_temp_volt_get_t param;

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_TEMP_VOLT, (int)(&param));
	CMD_LOG(1, "Temperature:%.02f°C\n", (float)param.Temperature / 16);
	CMD_LOG(1, "Voltage:%.02fV\n", (float)param.Voltage / 16);

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_temp_volt_auto_upload(char *cmd)
{
	int ret, cnt;
	int enable, period;

	cnt = cmd_sscanf(cmd, "e=%d p=%d", &enable, &period);
	if (cnt != 2) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}
	wlan_ext_temp_volt_auto_upload_set_t param;
	cmd_memset(&param, 0, sizeof(wlan_ext_temp_volt_auto_upload_set_t));
	param.Enable = enable;
	param.UploadPeriod = period;

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_TEMP_VOLT_AUTO_UPLOAD, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_temp_volt_thresh(char *cmd)
{
	int ret, cnt;
	int temp_high_en, temp_low_en, volt_high_en, volt_low_en;
	float temp_high_th, temp_low_th, volt_high_th, volt_low_th;

	cnt = cmd_sscanf(cmd, "THe=%d TH=%f TLe=%d TL=%f VHe=%d VH=%f VLe=%d VL=%f",
	                 &temp_high_en, &temp_high_th, &temp_low_en, &temp_low_th,
	                 &volt_high_en, &volt_high_th, &volt_low_en, &volt_low_th);
	if (cnt != 8) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}
	wlan_ext_temp_volt_thresh_set_t param;
	cmd_memset(&param, 0, sizeof(wlan_ext_temp_volt_thresh_set_t));
	param.TempHighEn = temp_high_en;
	param.TempHighThresh = temp_high_th * 16;
	param.TempLowEn = temp_low_en;
	param.TempLowThresh = temp_low_th * 16;
	param.VoltHighEn = volt_high_en;
	param.VoltHighThresh = volt_high_th * 16;
	param.VoltLowEn = volt_low_en;
	param.VoltLowThresh = volt_low_th * 16;
	param.TempVoltIndPeriod = 5;
	//param.TempVoltFallbackIndEn = 1;
	//param.TempUseDeltaEn = 1;
	//param.TempVoltFixedRefEn = 1;
	//param.TempJitterCnt = 50;

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_TEMP_VOLT_THRESH, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

#if NONCONNECT_SNIFF
static enum cmd_status cmd_wlan_set_rcv_special_frm(char *cmd)
{
	int ret;
	uint32_t enable, type;
	wlan_ext_rcv_spec_frm_param_set_t param;

	int cnt;
	cnt = cmd_sscanf(cmd, "e=%d t=0x%x", &enable, &type);
	if (cnt != 2) {
		CMD_ERR("cnt %d\n", cnt);
	}
	memset(&param, 0, sizeof(wlan_ext_rcv_spec_frm_param_set_t));
	param.Enable = enable;
	param.u32RecvSpecFrameCfg = type;

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_RCV_SPECIAL_FRM, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_send_raw_frm_cfg(char *cmd)
{
	int ret, cnt;
	uint32_t cfg, enable;
	wlan_ext_send_raw_frm_param_set_t param;

	cnt = cmd_sscanf(cmd, "e=%d c=0x%x", &enable, &cfg);
	if (cnt != 2) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	memset(&param, 0, sizeof(wlan_ext_send_raw_frm_param_set_t));
	param.Enable = enable;
	param.u16SendRawFrameCfg = cfg;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SEND_RAW_FRM_CFG, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_switch_channel_cfg(char *cmd)
{
	int ret, cnt;
	uint32_t band, flag, channel, sc_time;
	wlan_ext_switch_channel_param_set_t param;

	cnt = cmd_sscanf(cmd, "b=%d f=0x%x c=%d t=%d",
	                 &band, &flag, &channel, &sc_time);
	if (cnt != 4) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	memset(&param, 0, sizeof(wlan_ext_switch_channel_param_set_t));
	param.Enable = 1;
	param.Band = band;
	param.Flag = flag;
	param.ChannelNum = channel;
	param.SwitchChannelTime = sc_time;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SWITCH_CHN_CFG, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_get_cur_channel(char *cmd)
{
	int ret;
	uint32_t channel;

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_CURRENT_CHN, (int)(&channel));
	printf("current channel is %d\n", channel);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_sniff_kp_active(char *cmd)
{
	int ret, cnt;
	uint32_t enable, cfg;
	wlan_ext_sniff_kp_active_set_t param;

	cnt = cmd_sscanf(cmd, "e=%d c=0x%x", &enable, &cfg);
	if (cnt != 2) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	memset(&param, 0, sizeof(wlan_ext_sniff_kp_active_set_t));
	param.Enable = enable;
	param.u32Config = cfg;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SNIFF_KP_ACTIVE, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_sniff_auto_wakeup_host(char *cmd)
{
	int ret, cnt;
	int cfg, type, enable, wkp_time, kp_time, flag, start_time, channel;
	wlan_ext_sniff_sync_param_set_t param;

	cnt = cmd_sscanf(cmd, "cfg=0x%x t=0x%x e=%d c=%d wt=%d kt=%d f=0x%x st=%d",
	                 &cfg, &type, &enable, &channel, &wkp_time, &kp_time, &flag,
	                 &start_time);
	if (cnt != 8) {
		printf("cnt %d\n", cnt);
		//return CMD_STATUS_INVALID_ARG;
	}

	param.Enable = enable;
	param.ChannelNum = channel;
	param.SyncFrameType = type;//data
	param.u32SniffSyncCfg = cfg;// | SNIFF_SYNC_DISABLE_TIMER;
	param.time_sync_at_host.WakeupPeriod_ms = wkp_time;//ms
	param.time_sync_at_host.KeepActivePeriod_ms = kp_time;//ms
	param.time_sync_at_host.Flag = flag;//SNIFF_AUTO_WAKEUP_FRAME_SEND_TO_HOST;
	param.time_sync_at_host.StartTime = start_time;//us
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SNIFF_SYNC_CFG, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_sniff_auto_wakeup_wifi(char *cmd)
{
	int ret, cnt;
	int cfg, type, channel, flag, SyncDTIM, MaxLostSyncPacket;
	int TSFOffset, AdaptiveExpansion, KeepActiveNumAfterLostSync, ActiveTime, MaxAdaptiveExpansionLimit;
	int MaxKeepAliveTime;
	wlan_ext_sniff_sync_param_set_t param;

	cnt = cmd_sscanf(cmd, "cfg=0x%x t=0x%x c=%d f=0x%x d=%d ml=%d tsf=%d ae=%d kaa=%d at=%d ma=%d mk=%d",
	                 &cfg, &type, &channel, &flag, &SyncDTIM, &MaxLostSyncPacket, &TSFOffset,
	                 &AdaptiveExpansion, &KeepActiveNumAfterLostSync, &ActiveTime,
	                 &MaxAdaptiveExpansionLimit, &MaxKeepAliveTime);
	if (cnt != 12) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}
	param.Enable = 1;
	param.ChannelNum = channel;
	param.SyncFrameType = type;
	param.u32SniffSyncCfg = cfg;//s

	param.time_sync_at_wifi.Flag = flag;
	param.time_sync_at_wifi.SyncDTIM = SyncDTIM;
	param.time_sync_at_wifi.MaxLostSyncPacket = MaxLostSyncPacket;
	param.time_sync_at_wifi.TSFOffset = TSFOffset;
	param.time_sync_at_wifi.AdaptiveExpansion = AdaptiveExpansion;
	param.time_sync_at_wifi.KeepActiveNumAfterLostSync = KeepActiveNumAfterLostSync;
	param.time_sync_at_wifi.ActiveTime = ActiveTime;
	param.time_sync_at_wifi.MaxAdaptiveExpansionLimit = MaxAdaptiveExpansionLimit;
	param.time_sync_at_wifi.MaxKeepAliveTime = MaxKeepAliveTime;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SNIFF_SYNC_CFG, (int)(&param));

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static wlan_ext_frm_filter_set_t g_frm_filter;
static enum cmd_status cmd_wlan_rcv_frm_filter_mac(char *cmd)
{
	int ret = 0, cnt, i, filter;

	uint32_t A1[6];
	uint32_t A2[6];
	uint32_t A3[6];

	cnt = cmd_sscanf(cmd, "f=%d a1=%x:%x:%x:%x:%x:%x a2=%x:%x:%x:%x:%x:%x a3=%x:%x:%x:%x:%x:%x",
	                 &filter,
	                 &A1[0], &A1[1], &A1[2], &A1[3], &A1[4], &A1[5],
	                 &A2[0], &A2[1], &A2[2], &A2[3], &A2[4], &A2[5],
	                 &A3[0], &A3[1], &A3[2], &A3[3], &A3[4], &A3[5]);
	if (cnt != 19) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	if (filter == 1) {
		for (i = 0; i < 6; i++) {
			g_frm_filter.Filter1.MacAddrA1[i] = (uint8_t)A1[i];
			g_frm_filter.Filter1.MacAddrA2[i] = (uint8_t)A2[i];
			g_frm_filter.Filter1.MacAddrA3[i] = (uint8_t)A3[i];
		}
	} else if (filter == 2) {
		for (i = 0; i < 6; i++) {
			g_frm_filter.Filter2.MacAddrA1[i] = (uint8_t)A1[i];
			g_frm_filter.Filter2.MacAddrA2[i] = (uint8_t)A2[i];
			g_frm_filter.Filter2.MacAddrA3[i] = (uint8_t)A3[i];
		}
	} else {
		CMD_ERR("%s: invalid filter type:%d\n", __func__, filter);
		return CMD_STATUS_ACKED;
	}

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}
	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_frm_filter(char *cmd)
{
	int ret;

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_FRM_FILTER, (int)(&g_frm_filter));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_rcv_frm_filter1_ie_cfg(char *cmd)
{
	int ret = 0, cnt, i;
	rcv_frm_filter_t *param;
	param = &(g_frm_filter.Filter1);

	int enable, filter, and_mask, or_mask, frm_type, mac_mask, ie_id, ie_len;
	uint32_t oui[10];

	cnt = cmd_sscanf(cmd, "e=%d f=0x%x am=0x%x om=0x%x t=0x%x mm=0x%x ii=%d il=%d oui=%x %x %x %x %x %x %x %x %x %x ",
	    &enable, &filter, &and_mask, &or_mask, &frm_type, &mac_mask, &ie_id, &ie_len,
	    &oui[0], &oui[1], &oui[2], &oui[3], &oui[4],
	    &oui[5], &oui[6], &oui[7], &oui[8], &oui[9]);
	if (cnt != 18) {
		printf("cnt %d\n", cnt);
		if ((cnt == 6) || (cnt == 1)) {
			ie_len = 0;
		} else {
			return CMD_STATUS_INVALID_ARG;
		}
	}

	if (enable == 0) {
		g_frm_filter.Filter1Cfg = 0;
		cmd_memset(param, 0, sizeof(rcv_frm_filter_t));
		return CMD_STATUS_OK;
	}

	g_frm_filter.Filter1Cfg = 1;
	param->FilterEnable = filter;
	param->AndOperationMask = and_mask;
	param->OrOperationMask = or_mask;
	param->FrameType = frm_type;
	param->MacAddrMask = mac_mask;
	param->IeCfg.ElementId = ie_id;
	param->IeCfg.Length = ie_len;
	if (cnt >= 8) {
		//CMD_WRN("IE Id:%d, Len:%d\n", ie_id, ie_len);
		for (i = 0; i < ie_len; i++) {
			param->IeCfg.OUI[i] = (uint8_t)oui[i];
			//printf("OUI: num:%d origin::%x, set:%x\n", i, oui[i], param->IeCfg.OUI[i]);
		}
	}
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_rcv_frm_filter2_ie_cfg(char *cmd)
{
	int ret = 0, cnt, i;
	rcv_frm_filter_t *param;
	param = &(g_frm_filter.Filter2);

	int enable, filter, and_mask, or_mask, frm_type, mac_mask, ie_id, ie_len;
	uint32_t oui[10];

	cnt = cmd_sscanf(cmd, "e=%d f=0x%x am=0x%x om=0x%x t=0x%x mm=0x%x ii=%d il=%d oui=%x %x %x %x %x %x %x %x %x %x ",
	    &enable, &filter, &and_mask, &or_mask, &frm_type, &mac_mask, &ie_id, &ie_len,
	    &oui[0], &oui[1], &oui[2], &oui[3], &oui[4],
	    &oui[5], &oui[6], &oui[7], &oui[8], &oui[9]);
	if (cnt != 18) {
		printf("cnt %d\n", cnt);
		//return CMD_STATUS_INVALID_ARG;
	}

	if (enable == 0) {
		g_frm_filter.Filter2Cfg = 0;
		cmd_memset(param, 0, sizeof(rcv_frm_filter_t));
		return CMD_STATUS_OK;
	}

	g_frm_filter.Filter2Cfg = 1;
	param->FilterEnable = filter;
	param->AndOperationMask = and_mask;
	param->OrOperationMask = or_mask;
	param->FrameType = frm_type;
	param->MacAddrMask = mac_mask;
	param->IeCfg.ElementId = ie_id;
	param->IeCfg.Length = ie_len;
	for (i = 0; i < ie_len; i++) {
		param->IeCfg.OUI[i] = (uint8_t)oui[i];
	}

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_rcv_frm_filter1_pl_cfg(char *cmd)
{
	int ret = 0, cnt, i;
	rcv_frm_filter_t *param;
	param = &(g_frm_filter.Filter1);

	int enable, filter, and_mask, or_mask, frm_type, mac_mask, pl_offset, pl_len;
	uint32_t payload[10];

	cnt = cmd_sscanf(cmd, "e=%d f=0x%x am=0x%x om=0x%x t=0x%x mm=0x%x po=%d pl=%d p=%x %x %x %x %x %x %x %x %x %x ",
	    &enable, &filter, &and_mask, &or_mask, &frm_type, &mac_mask, &pl_offset, &pl_len,
	    &payload[0], &payload[1], &payload[2], &payload[3], &payload[4],
	    &payload[5], &payload[6], &payload[7], &payload[8], &payload[9]);
	if (cnt != 18) {
		printf("cnt %d\n", cnt);
		//return CMD_STATUS_INVALID_ARG;
	}

	if (enable == 0) {
		g_frm_filter.Filter1Cfg = 0;
		cmd_memset(param, 0, sizeof(rcv_frm_filter_t));
		return CMD_STATUS_ACKED;
	}

	g_frm_filter.Filter1Cfg = 1;
	param->FilterEnable = filter;
	param->AndOperationMask = and_mask;
	param->OrOperationMask = or_mask;
	param->FrameType = frm_type;
	param->MacAddrMask = mac_mask;
	param->PayloadCfg.PayloadOffset = pl_offset;
	param->PayloadCfg.PayloadLength = pl_len;
	for (i = 0; i < pl_len; i++) {
		param->PayloadCfg.Payload[i] = (uint8_t)payload[i];
	}

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_rcv_frm_filter2_pl_cfg(char *cmd)
{
	int ret = 0, cnt, i;
	rcv_frm_filter_t *param;
	param = &(g_frm_filter.Filter2);

	int enable, filter, and_mask, or_mask, frm_type, mac_mask, pl_offset, pl_len;
	uint32_t payload[10];

	cnt = cmd_sscanf(cmd, "e=%d f=0x%x am=0x%x om=0x%x t=0x%x mm=0x%x po=%d pl=%d p=%x %x %x %x %x %x %x %x %x %x ",
	    &enable, &filter, &and_mask, &or_mask, &frm_type, &mac_mask, &pl_offset, &pl_len,
	    &payload[0], &payload[1], &payload[2], &payload[3], &payload[4],
	    &payload[5], &payload[6], &payload[7], &payload[8], &payload[9]);
	if (cnt != 18) {
		printf("cnt %d\n", cnt);
		//return CMD_STATUS_INVALID_ARG;
	}

	if (enable == 0) {
		g_frm_filter.Filter2Cfg = 0;
		cmd_memset(param, 0, sizeof(rcv_frm_filter_t));
		return CMD_STATUS_ACKED;
	}

	g_frm_filter.Filter2Cfg = 1;
	param->FilterEnable = filter;
	param->AndOperationMask = and_mask;
	param->OrOperationMask = or_mask;
	param->FrameType = frm_type;
	param->MacAddrMask = mac_mask;
	param->PayloadCfg.PayloadOffset = pl_offset;
	param->PayloadCfg.PayloadLength = pl_len;
	for (i = 0; i < pl_len; i++) {
		param->PayloadCfg.Payload[i] = (uint8_t)payload[i];
	}

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}


#define FRM_TYPE_ASRQ       (0)
#define FRM_TYPE_ASRSP      (1)
#define FRM_TYPE_RSRQ       (2)
#define FRM_TYPE_RSRSP      (3)
#define FRM_TYPE_PBRQ       (4)
#define FRM_TYPE_PBRSP      (5)
#define FRM_TYPE_BCN        (6)
#define FRM_TYPE_ATIM       (7)
#define FRM_TYPE_DAS        (8)
#define FRM_TYPE_AUTH       (9)
#define FRM_TYPE_DAUTH      (10)
#define FRM_TYPE_ACTION     (11)
#define FRM_TYPE_NULLDATA   (12)
#define FRM_TYPE_DATA       (13)
#define FRM_TYPE_QOSDATA    (14)
#define FRM_TYPE_ARPREQ     (15)
#define FRM_TYPE_SA_QUERY   (16)
#define FRM_TYPE_MANAGER    (17)
#define FRM_TYPE_ALL_DATA   (18)
#define FRM_TYPE_MAX        (19)

static wlan_ext_temp_frm_set_t frm;
static uint8_t bssid[6] = {0x14, 0x72, 0x58, 0x36, 0x90, 0xaa};
static uint8_t src_mac[6] = {0x14, 0x72, 0x58, 0x36, 0x90, 0xaa};
static uint8_t dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static const char *ssid = "AP_test";
static uint8_t ap_channel = 1;
static uint8_t src_ip[4] = {192, 168, 51, 123};

void buf_dump(unsigned char *buf, int len)
{
	int i;
	for (i = 1; i < len + 1; i++) {
		printf("%02X ", buf[i-1]);
		if (i % 16 == 0) {
			printf("\n");
		}
	}
}

void construct_frame(int frm_type)
{
	switch (frm_type) {
	case FRM_TYPE_ASRQ:
		frm.FrmLength = wlan_construct_assocreq((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid, (uint8_t *)ssid, strlen(ssid));
		printf("send raw frame associate req (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_ASRSP:
		frm.FrmLength = wlan_construct_assocrsp((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame associate rsp (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_RSRQ:
		frm.FrmLength = wlan_construct_reassocreq((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid, (uint8_t *)ssid, strlen(ssid));
		printf("send raw frame reassociate req (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_RSRSP:
		frm.FrmLength = wlan_construct_reassocrsp((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame reassociate rsp (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_PBRQ:
		frm.FrmLength = wlan_construct_probereq((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid, (uint8_t *)ssid, strlen(ssid));
		printf("send raw frame probe req (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_PBRSP:
		frm.FrmLength = wlan_construct_probersp((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid, (uint8_t *)ssid, strlen(ssid), ap_channel);
		printf("send raw frame probe rsp (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_BCN:
		frm.FrmLength = wlan_construct_beacon((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid, (uint8_t *)ssid, strlen(ssid), ap_channel);
		printf("send raw frame beacon (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_ATIM:
		frm.FrmLength = wlan_construct_atim((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame atim (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_DAS:
		frm.FrmLength = wlan_construct_disassocreq((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame disassociate req (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_AUTH:
		frm.FrmLength = wlan_construct_auth((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame auth (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_DAUTH:
		frm.FrmLength = wlan_construct_deauth((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame deauth (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_ACTION:
		frm.FrmLength = wlan_construct_action((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame action (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_NULLDATA:
		frm.FrmLength = wlan_construct_nulldata((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame nulldata (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_DATA:
		frm.FrmLength = wlan_construct_data((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame data (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_QOSDATA:
		frm.FrmLength = wlan_construct_qosdata((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame qosdata (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_ARPREQ:
		frm.FrmLength = wlan_construct_arpreq((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid, src_ip);
		printf("send raw frame arp req (%d)\n", frm.FrmLength);
		break;
	case FRM_TYPE_SA_QUERY:
		frm.FrmLength = wlan_construct_sa_query((uint8_t *)frm.Frame, MAX_FRM_LEN, src_mac, dest_mac, bssid);
		printf("send raw frame sa query (%d)\n", frm.FrmLength);
		break;
	}
}

static enum cmd_status cmd_wlan_set_temp_frm(char *cmd)
{
	int ret, cnt, frm_type;
	cnt = cmd_sscanf(cmd, "t=%d", &frm_type);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}
	construct_frame(frm_type);
	if (frm_type != FRM_TYPE_BCN && frm_type != FRM_TYPE_PBRSP) {
		printf("force add TSF\n");
		for (int i = 0; i < frm.FrmLength - 24; i++) {
			frm.Frame[frm.FrmLength - 1 - i + 10] = frm.Frame[frm.FrmLength - 1 - i];
		}
		frm.Frame[32] = 0x64;
		frm.Frame[33] = 0;
		frm.FrmLength += 10;
	}

	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_TEMP_FRM, (int)(&frm));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_send_sync_frm(char *cmd)
{
	int ret, cnt;
	uint32_t bcn_intvl, enable;
	wlan_ext_send_sync_frm_set_t param;

	cnt = cmd_sscanf(cmd, "e=%d b=%d", &enable,
	                &bcn_intvl);
	if (cnt != 2) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	memset(&param, 0, sizeof(wlan_ext_send_sync_frm_set_t));
	param.Enable = enable;
	param.BcnInterval = bcn_intvl;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SYNC_FRM_SEND, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_send_raw_frm(char *cmd)
{
	int ret = 0, i, j, cnt, ext_ch, cur_ch, tmp_ch;
	int frm_cnt, frm_period, frm_type;
	uint32_t mac_sa[6];
	uint32_t mac_da[6];
	uint32_t mac_bssid[6];

	cnt = cmd_sscanf(cmd, "c=%d p=%d t=%d ec=%d da=%x:%x:%x:%x:%x:%x sa=%x:%x:%x:%x:%x:%x bssid=%x:%x:%x:%x:%x:%x",
	                 &frm_cnt, &frm_period, &frm_type, &ext_ch,
	                 &mac_da[0], &mac_da[1], &mac_da[2], &mac_da[3], &mac_da[4], &mac_da[5],
	                 &mac_sa[0], &mac_sa[1], &mac_sa[2], &mac_sa[3], &mac_sa[4], &mac_sa[5],
	                 &mac_bssid[0], &mac_bssid[1], &mac_bssid[2], &mac_bssid[3], &mac_bssid[4], &mac_bssid[5]);
	if (cnt < 4) {
		CMD_ERR("invalid param cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}
	if (cnt >= 10) {
		for (i = 0; i < 6; i++)
			dest_mac[i] = (uint8_t)mac_da[i];
	}
	if (cnt >= 16) {
		for (i = 0; i < 6; i++)
			src_mac[i] = (uint8_t)mac_sa[i];
	}
	if (cnt == 22) {
		for (i = 0; i < 6; i++)
			bssid[i] = (uint8_t)mac_bssid[i];
	}
	printf("dest mac address:%02x:%02x:%02x:%02x:%02x:%02x\n",
	       dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5]);
	printf("src mac address:%02x:%02x:%02x:%02x:%02x:%02x\n",
	       src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]);
	printf("bssid address:%02x:%02x:%02x:%02x:%02x:%02x\n",
	       bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);

	switch (frm_type) {
	case FRM_TYPE_MANAGER:
		printf("send all manager frame\n");
		cnt = 0;
		for (i = 0; i < frm_cnt; i++) {
			for (j = 0; j < 12; j++) {
				cmd_memset((uint8_t *)frm.Frame, 0, MAX_FRM_LEN);
				construct_frame(j);
				wlan_send_raw_frame(g_wlan_netif, IEEE80211_FC_STYPE_AUTH, (uint8_t *)frm.Frame, frm.FrmLength);
				OS_MSleep(frm_period);
				printf("******************************** cnt:%d ********************************\n", cnt++);
			}
		}
		return CMD_STATUS_OK;
	case FRM_TYPE_ALL_DATA:
		printf("send all data frame\n");
		cnt = 0;
		for (i = 0; i < frm_cnt; i++) {
			for (j = 0; j < 6; j++)
				dest_mac[j] = (uint8_t)mac_da[j];
			for (j = 12; j < 15; j++) {
				cmd_memset((uint8_t *)frm.Frame, 0, MAX_FRM_LEN);
				construct_frame(j);
				wlan_send_raw_frame(g_wlan_netif, IEEE80211_FC_STYPE_AUTH, (uint8_t *)frm.Frame, frm.FrmLength);
				OS_MSleep(frm_period);
				printf("******************************** cnt:%d ********************************\n", cnt++);
			}
			//send broadcast data frame
			cmd_memset(dest_mac, 0xff, 6);
			cmd_memset((uint8_t *)frm.Frame, 0, MAX_FRM_LEN);
			construct_frame(FRM_TYPE_DATA);
			wlan_send_raw_frame(g_wlan_netif, IEEE80211_FC_STYPE_AUTH, (uint8_t *)frm.Frame, frm.FrmLength);
			OS_MSleep(frm_period);
			printf("******************************** cnt:%d ********************************\n", cnt++);
		}
		return CMD_STATUS_OK;
	case FRM_TYPE_MAX:
		{
			printf("send all frame\n");
			wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_CURRENT_CHN, (int)(&cur_ch));
			wlan_ext_switch_channel_param_set_t param1;
			memset(&param1, 0, sizeof(wlan_ext_switch_channel_param_set_t));
			param1.Enable = 1;
			param1.SwitchChannelTime = 5000;//SEND_RAW_FRAME_MAX_SWITCH_CHANNEL_TIME;
			cnt = 0;
			for (i = 0; i < frm_cnt; i++) {
				for (j = 0; j < 6; j++)
					dest_mac[j] = (uint8_t)mac_da[j];
				for (j = 0; j < 17; j++) {
					cmd_memset((uint8_t *)frm.Frame, 0, MAX_FRM_LEN);
					construct_frame(j);
					wlan_send_raw_frame(g_wlan_netif, IEEE80211_FC_STYPE_AUTH, (uint8_t *)frm.Frame, frm.FrmLength);
					OS_MSleep(frm_period);
					if (ext_ch) {
						param1.ChannelNum = ext_ch;
						wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SWITCH_CHN_CFG, (int)(&param1));
						do {
							OS_MSleep(10);
							wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_CURRENT_CHN, (int)(&tmp_ch));
						} while (tmp_ch != ext_ch);
						printf("switch to channel %d\n", ext_ch);
						wlan_send_raw_frame(g_wlan_netif, IEEE80211_FC_STYPE_AUTH, (uint8_t *)frm.Frame, frm.FrmLength);
						OS_MSleep(100);
						param1.ChannelNum = cur_ch;
						wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SWITCH_CHN_CFG, (int)(&param1));
						do {
							OS_MSleep(5);
							wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_CURRENT_CHN, (int)(&tmp_ch));
						} while (tmp_ch != cur_ch);
						printf("switch to channel %d\n", cur_ch);
						OS_MSleep(frm_period);
					}
					printf("******************************** cnt:%d ********************************\n", cnt++);
				}
				cmd_memset(dest_mac, 0xff, 6);
				cmd_memset((uint8_t *)frm.Frame, 0, MAX_FRM_LEN);
				construct_frame(FRM_TYPE_DATA);
				wlan_send_raw_frame(g_wlan_netif, IEEE80211_FC_STYPE_AUTH, (uint8_t *)frm.Frame, frm.FrmLength);
				OS_MSleep(frm_period);
				if (ext_ch) {
					param1.ChannelNum = ext_ch;
					wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SWITCH_CHN_CFG, (int)(&param1));
					do {
						OS_MSleep(10);
						wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_CURRENT_CHN, (int)(&tmp_ch));
					} while (tmp_ch != ext_ch);
					printf("switch to channel %d\n", ext_ch);
					wlan_send_raw_frame(g_wlan_netif, IEEE80211_FC_STYPE_AUTH, (uint8_t *)frm.Frame, frm.FrmLength);
					OS_MSleep(100);
					param1.ChannelNum = cur_ch;
					wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SWITCH_CHN_CFG, (int)(&param1));
					do {
						OS_MSleep(5);
						wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_CURRENT_CHN, (int)(&tmp_ch));
					} while (tmp_ch != cur_ch);
					printf("switch to channel %d\n", cur_ch);
					OS_MSleep(frm_period);
				}
				printf("******************************** cnt:%d ********************************\n", cnt++);
			}
		}
		return CMD_STATUS_OK;
	default:
		construct_frame(frm_type);
		break;
	}
	buf_dump((uint8_t *)frm.Frame, frm.FrmLength);

	for (i = 0; i < frm_cnt; i++) {
		ret = wlan_send_raw_frame(g_wlan_netif, IEEE80211_FC_STYPE_AUTH, (uint8_t *)frm.Frame, frm.FrmLength);
		printf("cnt:%d\n", i+1);
		if (ret == -1) {
			CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
			return CMD_STATUS_ACKED;
		}
		OS_MSleep(frm_period);
	}

	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_sniff_ext_param(char *cmd)
{
	int ret, cnt;
	int enable, retry, expenRight, dtim;
	wlan_ext_sniff_extern_param_set_t param;

	cnt = cmd_sscanf(cmd, "e=0x%x r=%d er=%d d=%d",
	                 &enable, &retry, &expenRight, &dtim);
	if (cnt != 4) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}

	param.SniffExtFuncEnable = enable;
	param.SniffRetryAfterLostSync = retry;
	param.SniffAdaptiveExpenRight = expenRight;
	param.SniffRetryDtim = dtim;
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SNIFF_EXTERN_CFG, (int)(&param));
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_get_rcv_stat(char *cmd)
{
	int ret, i;
	unsigned int sum_cnt = 0;
	int sum_avg = 0;
	wlan_ext_bcn_status_t bcn_status;

	char dly_info[][20] = {
		"(<0      )",
		"(<500us  )",
		"(<1000us )",
		"(<2000us )",
		"(<4000us )",
		"(<8000us )",
		"(<16000us)",
		"(>16000us)",
	};

	cmd_memset(&bcn_status, 0, sizeof(wlan_ext_bcn_status_t));
	ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_SNIFF_STAT, (uint32_t)&bcn_status);
	if (ret == -2) {
		CMD_ERR("%s: command '%s' invalid arg\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	} else if (ret == -1) {
		CMD_ERR("%s: command '%s' exec failed\n", __func__, cmd);
		return CMD_STATUS_ACKED;
	}

	printf("\nAPP AP Beacon Delay Stat Info=================\n");
	for (i = 0; i < 8; i++) {
		printf("cnt %d %s: %d\n",
		       i, dly_info[i],
		       bcn_status.bcn_delay_cnt[i]);
		sum_cnt += bcn_status.bcn_delay_cnt[i];
	}

	if (sum_cnt) {
		sum_avg = bcn_status.bcn_delay_sum / sum_cnt;
	}

	printf("Dur: %d, Max: 0x%X, Rxed: %d, Missed: 0x%X\n",
	       bcn_status.bcn_duration,
	       bcn_status.bcn_delay_max,
	       bcn_status.bcn_rx_cnt,
	       bcn_status.bcn_miss_cnt);
	printf("Sum: %d, Cnt: %d, Ava: %d\n",
	       bcn_status.bcn_delay_sum,
	       sum_cnt,
	       sum_avg);
	printf("APP AP Beacon Delay Stat Info=================\n");

	return CMD_STATUS_OK;
}

static uint32_t g_frm_rcv_cnt = 0;
static uint32_t g_frm_rcv_mac_cnt = 0;
void sta_rx_cb(uint8_t *data, uint32_t len, void *info)
{
	if (!info) {
		printf("%s(), info NULL\n", __func__);
		return;
	}

	struct ieee80211_frame *wh;
	uint8_t filter_mac[6] = {0x14, 0x72, 0x58, 0x36, 0x90, 0xaa};
	wh = (struct ieee80211_frame *)data;
	g_frm_rcv_cnt++;
	if (memcmp(wh->i_addr3, filter_mac, 6) == 0) {
		g_frm_rcv_mac_cnt++;
	}
	char *str_frm_type;
	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
	case IEEE80211_FC0_TYPE_MGT:
		switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
		case IEEE80211_FC_STYPE_ASSOC_REQ:
			str_frm_type = "association req";
			break;
		case IEEE80211_FC_STYPE_ASSOC_RESP:
			str_frm_type = "association resp";
			break;
		case IEEE80211_FC_STYPE_REASSOC_REQ:
			str_frm_type = "reassociation req";
			break;
		case IEEE80211_FC_STYPE_REASSOC_RESP:
			str_frm_type = "reassociation resp";
			break;
		case IEEE80211_FC_STYPE_PROBE_REQ:
			str_frm_type = "probe req";
			break;
		case IEEE80211_FC_STYPE_PROBE_RESP:
			str_frm_type = "probe resp";
			break;
		case IEEE80211_FC_STYPE_BEACON:
			str_frm_type = "beacon";
			break;
		case IEEE80211_FC_STYPE_ATIM:
			str_frm_type = "atim";
			break;
		case IEEE80211_FC_STYPE_DISASSOC:
			str_frm_type = "disassociation";
			break;
		case IEEE80211_FC_STYPE_AUTH:
			str_frm_type = "authentication";
			break;
		case IEEE80211_FC_STYPE_DEAUTH:
			str_frm_type = "deauthentication";
			break;
		case IEEE80211_FC_STYPE_ACTION:
			str_frm_type = "action";
			break;
		default:
			str_frm_type = "unknown mgmt";
			break;
		}
		break;
	case IEEE80211_FC0_TYPE_CTL:
		str_frm_type = "control";
		break;
	case IEEE80211_FC0_TYPE_DATA:
#if 0
		switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
		case IEEE80211_FC0_SUBTYPE_DATA:
			str_frm_type = "data";
			break;
		case IEEE80211_FC0_SUBTYPE_QOS:
			str_frm_type = "qos data";
			break;
		case IEEE80211_FC0_SUBTYPE_NODATA:
			str_frm_type = "null data";
			break;
		default:
			str_frm_type = "unknown data";
			break;
		}
#else
		str_frm_type = "data";
#endif
		break;
	default:
		str_frm_type = "unknown";
		break;
	}
	printf("recv pack type:%s cnt:%d, mac cnt:%d, len:%d\n",
	       str_frm_type, g_frm_rcv_cnt, g_frm_rcv_mac_cnt, len);
}

static enum cmd_status cmd_wlan_set_rcv_cb(char *cmd)
{
	int cnt, enable;

	cnt = cmd_sscanf(cmd, "e=%d", &enable);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}
	if (enable)
		wlan_monitor_set_rx_cb(g_wlan_netif, sta_rx_cb);
	else
		wlan_monitor_set_rx_cb(g_wlan_netif, NULL);
	return CMD_STATUS_OK;
}

static enum cmd_status cmd_wlan_set_even_ie(char *cmd)
{
	int cnt, enable;
	uint8_t ie[7] = {0xDD, 0x05, 0x00, 0x50, 0xF2, 0x05, 0x01};

	cnt = cmd_sscanf(cmd, "e=%d", &enable);
	if (cnt != 1) {
		CMD_ERR("cnt %d\n", cnt);
		return CMD_STATUS_INVALID_ARG;
	}
	if (enable) {
		ie[6]++;
		printf("Set event beacon!\n");
		wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_UPDATE_TEMP_IE, (int)(ie));
	} else {
		printf("Set normal beacon!\n");
		wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_UPDATE_TEMP_IE, (int)(ie));
	}
	return CMD_STATUS_OK;
}

#endif /* NONCONNECT_SNIFF */

/*
 * wlan commands
 */

static enum cmd_status cmd_wlan_help_exec(char *cmd);

static const struct cmd_data g_wlan_cmds[] = {
	{ "pm_dtim",                cmd_wlan_set_pm_dtim },
	{ "get_pm_dtim",            cmd_wlan_get_pm_dtim },
	{ "set_lsn_intv",           cmd_wlan_set_listen_interval },
	{ "ps_mode",                cmd_wlan_set_ps_mode },
	{ "pm",                     cmd_wlan_pm },
	{ "ampdu",                  cmd_wlan_set_ampdu },
	{ "retry",                  cmd_wlan_set_retry },
	{ "null_prd",               cmd_wlan_set_pm_tx_null_period },
	{ "bcn_win_cfg",            cmd_wlan_set_bcn_win_cfg },
	{ "bcn_win",                cmd_wlan_set_bcn_win_us },
	{ "get_bcn_stat",           cmd_wlan_get_bcn_stat },
	{ "get_cur_rate",           cmd_wlan_get_cur_tx_rate },
	{ "get_cur_signal",         cmd_wlan_get_cur_signal },
	{ "scan_freq",              cmd_wlan_scan_freq },
	{ "set_scan_param",         cmd_wlan_set_scan_param },
	{ "get_temp_volt",          cmd_wlan_get_temp_volt },
	{ "set_tv_upload",          cmd_wlan_set_temp_volt_auto_upload },
	{ "set_tv_thresh",          cmd_wlan_set_temp_volt_thresh },
#if NONCONNECT_SNIFF
	{ "rcv_spec_frm",           cmd_wlan_set_rcv_special_frm },
	{ "raw_frm_cfg",            cmd_wlan_send_raw_frm_cfg },
	{ "sniff_kp_active",        cmd_wlan_sniff_kp_active },
	{ "sniff_auto_wkp_host",    cmd_wlan_set_sniff_auto_wakeup_host },
	{ "sniff_auto_wkp_wifi",    cmd_wlan_set_sniff_auto_wakeup_wifi },
	{ "send_raw_frm",           cmd_wlan_send_raw_frm },
	{ "switch_chn",             cmd_wlan_switch_channel_cfg },
	{ "get_chn",                cmd_wlan_get_cur_channel },
	{ "rcv_filter_mac",         cmd_wlan_rcv_frm_filter_mac },
	{ "set_frm_filter",         cmd_wlan_set_frm_filter },
	{ "rcv_filter1_ie",         cmd_wlan_rcv_frm_filter1_ie_cfg },
	{ "rcv_filter2_ie",         cmd_wlan_rcv_frm_filter2_ie_cfg },
	{ "rcv_filter1_pl",         cmd_wlan_rcv_frm_filter1_pl_cfg },
	{ "rcv_filter2_pl",         cmd_wlan_rcv_frm_filter2_pl_cfg },
	{ "set_temp_frm",           cmd_wlan_set_temp_frm },
	{ "send_sync_frm",          cmd_wlan_send_sync_frm },
	{ "set_ext_param",          cmd_wlan_set_sniff_ext_param },
	{ "get_rcv_stat",           cmd_wlan_get_rcv_stat },
	{ "set_rcv_cb",             cmd_wlan_set_rcv_cb },
	{ "set_even_ie",            cmd_wlan_set_even_ie },
#endif
	{ "help",                   cmd_wlan_help_exec },
};

static enum cmd_status cmd_wlan_help_exec(char *cmd)
{
	return cmd_help_exec(g_wlan_cmds, cmd_nitems(g_wlan_cmds), 16);
}

enum cmd_status cmd_wlan_exec(char *cmd)
{
	if (g_wlan_netif == NULL) {
		return CMD_STATUS_FAIL;
	}
	return cmd_exec(cmd, g_wlan_cmds, cmd_nitems(g_wlan_cmds));
}
#endif /* PRJCONF_NET_EN */
#endif /* __CONFIG_WLAN */
